package com.nit.store.security.filter;

import com.alibaba.fastjson.JSON;
import com.nit.store.web.JsonResult;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@Slf4j
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Value("${jwt.secret}")
    private String secretKey;
    @Value("Bearer")
    private String jwtHeader;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //客户端在使用JWT时 应该将其添加在请求中 名为Authentication属性中 -- 客户端必须蹲守这个规范
        //从请求头中获取名为Authentication的数据
        //约定：有效的jwt数据要求 带有指定的开头"Bearer",开头不包含在jwt数据中
        String requestUrl = request.getRequestURI();
        System.out.println(requestUrl);
        String authHeader = request.getHeader("Authentication");
        System.out.println("从请求头中获取Authentication："+authHeader);

        //判断是否获取到了数据且该数据是否有效
        if(StringUtils.hasText(authHeader) && authHeader.startsWith(jwtHeader)){
            System.out.println("准备解析jwt数据........");
            String jwt = authHeader.substring(jwtHeader.length()); //
            System.out.println("从请求头中获取jwt:"+jwt);
            String username = null;
            String permissionString = null;
            Long uid = null;
            try {
                JwtParser parser = Jwts.parser();
                //获取数据 claims
                Claims claims = parser.setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
                uid = Long.parseLong(claims.get("uid").toString());
                username = claims.get("username").toString();
                permissionString = claims.get("permissions").toString();
                System.out.println("从jwt中解析得到uid:"+uid);
                System.out.println("从jwt中解析得到username:"+username);
                System.out.println("从jwt中解析得到permissions:"+permissionString);
                // 将用户的权限信息json字符串  转换为Spring Security要求的List<GrantedAuthority>类型的数据
                List<SimpleGrantedAuthority> authories =
                        JSON.parseArray(permissionString, SimpleGrantedAuthority.class);
                System.out.println("将json格式的权限信息转换为集合："+authories);
                //将解析成功的jwt数据 放回到spring Security中
                Authentication authentication =
                        new UsernamePasswordAuthenticationToken(username,null,authories);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                System.out.println("成功将jwt数据存入到Spring Security上下文.....");
                //继续执行后续的过滤器链
                filterChain.doFilter(request,response);

            }catch (ExpiredJwtException e){
                log.error("解析失败，jwt数据已经过期！");
                JsonResult<Void> jsonResult = JsonResult.fail(JsonResult.State.ERR_FORBIDDEN,"登录超时，请重新登录！");
                String jsonResultString = JSON.toJSONString(jsonResult);
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().println(jsonResultString);
            }catch (NullPointerException e){
                e.printStackTrace();
                log.info(e.getMessage());
                log.error("出问题辣请联系管理员~");
                JsonResult<Void> jsonResult = JsonResult.fail(JsonResult.State.ERR_FORBIDDEN,"jwt数据有误，请重新登录！");
                String jsonResultString = JSON.toJSONString(jsonResult);
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().println(jsonResultString);
            }
        }
        else{
            //因为某些请求本身也不要求登录，没有jwt是正常表现
            System.out.println("没有获取到jwt数据,直接放行............");
            //继续执行后续的过滤器链
            filterChain.doFilter(request,response);
        }


    }
}
